package es.deusto.ingenieria.aike.formulation;

import java.io.File;
import java.io.IOException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import es.deusto.ingenieria.aike.search.heuristic.BestFSwithLog;
import es.deusto.ingenieria.ingenieria.search.SearchMethod;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;



public class parkingLotMaze {

	private static Cell[][] maze;
	private static parkingState firstState;
	private static parkingState finalState;
	private static int crossCoords[];
	
	private static int cols=0;
	private static int rows=0;
    private static int carPosRow=0;
	private static int carPosCol=0;
	private static int flagPosRow=0;
	private static int flagPosCol=0;
	private static boolean leftFlagWall= false;
	private static boolean rightFlagWall= false;
	private static boolean topFlagWall= false;
	private static boolean bottomFlagWall= false;
	private static String orientation;
	
	public static void main(String[] args) {
		
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 
		DocumentBuilder docBuilder;
		String aux="";
		int crossCol;
		int crossRow;
		int index=0;
		try {
			
			//Creating the first state from the XML file			
			NodeList nList;
			NamedNodeMap nAtt;
			Node node;
			
			docBuilder = docBuilderFactory.newDocumentBuilder();
//			org.w3c.dom.Document doc = docBuilder.parse (new File("./xml/parkinglotmaze1.xml"));
			org.w3c.dom.Document doc = docBuilder.parse (new File(args[0]));
			
			nList=doc.getElementsByTagName("aike:maze");
			nAtt = nList.item(0).getAttributes();
			node=nAtt.getNamedItem("rows");
			rows=Integer.parseInt(node.getNodeValue());
			node=nAtt.getNamedItem("columns");
			cols=Integer.parseInt(node.getNodeValue());

			nList=doc.getElementsByTagName("aike:car");
			nAtt = nList.item(0).getAttributes();
			node=nAtt.getNamedItem("row");
			carPosRow=Integer.parseInt(node.getNodeValue());
			node=nAtt.getNamedItem("column");
			carPosCol=Integer.parseInt(node.getNodeValue());
			
			nList=doc.getElementsByTagName("aike:flag");
			nAtt=nList.item(0).getAttributes();
			node=nAtt.getNamedItem("row");
			flagPosRow=Integer.parseInt(node.getNodeValue());
			node=nAtt.getNamedItem("column");
			flagPosCol=Integer.parseInt(node.getNodeValue());
			
			node=nAtt.getNamedItem("left-wall");
			aux=node.getNodeValue();
			if (aux.compareToIgnoreCase("yes")==0){
				leftFlagWall=true;
			}
			
			node=nAtt.getNamedItem("top-wall");
			aux=node.getNodeValue();
			if (aux.compareToIgnoreCase("yes")==0){
				topFlagWall=true;
			}
			
			node=nAtt.getNamedItem("right-wall");
			aux=node.getNodeValue();
			if (aux.compareToIgnoreCase("yes")==0){
				rightFlagWall=true;
			}
			
			node=nAtt.getNamedItem("bottom-wall");
			aux=node.getNodeValue();
			if (aux.compareToIgnoreCase("yes")==0){
				bottomFlagWall=true;
			}
			
			nList=doc.getElementsByTagName("aike:cross");
			crossCoords=new int[nList.getLength()*2];	
			for (int i=0;i<nList.getLength();i++){
				nAtt=nList.item(i).getAttributes();
				node=nAtt.getNamedItem("row");
				crossRow=Integer.parseInt(node.getNodeValue());
				node=nAtt.getNamedItem("column");
				crossCol=Integer.parseInt(node.getNodeValue());
				crossCoords[index]=crossRow;
				index++;
				crossCoords[index]=crossCol;
				index++;
			}
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		
		//Make a instance of this class to use its methods
		
		parkingLotMaze plm=new parkingLotMaze();
		
        //Use the methods of this class to initilize the firs state
		
		plm.initMaze();
		plm.calculateInitOrientation();
		plm.putCrossesOnMaze(crossCoords);
		plm.setInitialCarPosition();
		plm.setFlagOnMaze();
		
		System.out.println("Initial orientation: "+orientation);
		System.out.println("Flag coords: "+flagPosRow+" "+flagPosCol);
		System.out.println("Flag wall:  up: "+ topFlagWall+ "  right: "+rightFlagWall+"  bottom: "+bottomFlagWall+ "  left: "+leftFlagWall);
		
		//Instance of the class problem to initialize it and start resolving the problem
		ParkingProblem problem = new ParkingProblem();		
		firstState=new parkingState (maze, carPosRow, carPosCol, orientation, flagPosRow, flagPosCol);
		problem.addInitialState(new State (firstState));
		finalState= new parkingState( maze, flagPosRow, flagPosCol, plm.calculateFinalCarOrientation(), flagPosRow, flagPosCol);
		problem.addFinalState(new State(finalState));
		SearchMethod search= new BestFSwithLog(new Heuristic());
		problem.solve(search);
	}
	
	
	private void initMaze(){
		
		//This method initialize the maze and sets the surrounding walls
		
		maze=new Cell[rows+2][cols+2];
		for (int i=0; i<rows+2;i++){
			for (int j=0; j<cols+2;j++){
				maze[i][j]=new Cell();
			}
		}
				
		for (int i=1; i<=rows; i++){
			maze[i][1].setLeftWall(true);
			maze[i][cols].setRightWall(true);
		}
		for (int i=1; i<=cols; i++){
			maze[1][i].setTopWall(true);
			maze[rows][i].setBottomWall(true);
		}
		
	}
	
	private void calculateInitOrientation(){
		
		//This method calculates the initial orientation of the car using its initial position 
		
		if(carPosRow>rows){
			orientation="NORTH";	
		}
		else if (carPosRow<1){
			orientation="SOUTH";
		}
		else if (carPosCol<1){
			orientation="EAST";
		}
		else orientation="WEST";
	}
	
	private void putCrossesOnMaze(int[] coords){
		
		//This method puts the crosses on the maze using the previously calculated vector 
		
		for (int i=0;i<coords.length-1;i=i+2){
			maze[coords[i]][coords[i+1]].setCross(true);
		}
	}
	
	private void setInitialCarPosition(){
		
		//This method puts the car in the initial position of the maze 
		
		if (orientation=="NORTH"){
			carPosRow=carPosRow-1;
		}
		else if (orientation=="SOUTH"){
			carPosRow=carPosRow+1;
		}
		else if (orientation=="EAST"){
			carPosCol=carPosCol+1;
		}
		else carPosCol=carPosCol-1;
	}
	
	public void setFlagOnMaze(){
		
		//This method puts the flag on the maze and its own walls 
		
		maze[flagPosRow][flagPosCol].setGoal(true);
		maze[flagPosRow][flagPosCol].setLeftWall(leftFlagWall);
		maze[flagPosRow][flagPosCol].setRightWall(rightFlagWall);
		maze[flagPosRow][flagPosCol].setTopWall(topFlagWall);
		maze[flagPosRow][flagPosCol].setBottomWall(bottomFlagWall);
		if (rightFlagWall){
			maze[flagPosRow][flagPosCol+1].setLeftWall(true);
		}
		if (leftFlagWall){
			maze[flagPosRow][flagPosCol-1].setRightWall(true);
		}
		if (topFlagWall){
			maze[flagPosRow-1][flagPosCol].setBottomWall(true);
		}
		if (bottomFlagWall){
			maze[flagPosRow+1][flagPosCol].setTopWall(true);
		}
	}
	
	private String calculateFinalCarOrientation(){
		
		//This method calculates the final orientation of the car using the walls surrounding the flag		
		
		String finalOrient="";
		if (!leftFlagWall){
			finalOrient="EAST";
		}
		else if (!rightFlagWall){
			finalOrient="WEST";
		}
		else if (!topFlagWall){
			finalOrient="SOUTH";
		}
		else finalOrient="NORTH";
		
		return finalOrient;
	}
}


